#include "stdafx.h"
#include "cppflibinc.h"


using namespace cppflib;
using namespace cppflib::os;
using namespace cppflib::exceptions;
using namespace cppflib::collections;
using namespace cppflib::database::sqlite;
using namespace cppflib::database;
using namespace cppflib::lang;
using namespace cppflib::util;


static ListCppObjT<CFString> * toListObj(pcwstr_t *table)
{
   ListCppObjT<CFString> * listObj = new ListCppObjT<CFString>();
   for (int i = 0; table[i] != NULL; ++i)
      listObj->AddTail(new CFString(table[i]));

   return listObj;
}

static void TestSQLStr()
{
   cppmempool::MemPoolWrap localPool;

   // create table
   pcwstr_t tableSchema[] = { 
                               _S("key"), _S("TEXT PRIMARY KEY"), 
                               _S("start"), _S("INTEGER"), 
                               _S("end"), _S("INTEGER"), 
                               _S("Synopsis_en"), _S("TEXT"),
                               _S("Synopsis_zh"), _S("TEXT"),
                               _S("ProgName_en"), _S("TEXT"),
                               _S("ProgName_zh"), _S("TEXT"),
                               NULL
                            };

   ListCppObjT<CFString> * schemaList = toListObj(tableSchema);
   const CFString * createString = SQLStr::GenCreateTable(CFString(_S("Synopsis")), *schemaList);
   assert(createString->Compare(_S("CREATE TABLE Synopsis (key TEXT PRIMARY KEY,start INTEGER,end INTEGER,Synopsis_en TEXT,Synopsis_zh TEXT,ProgName_en TEXT,ProgName_zh TEXT)")) == 0);

   // drop table
   const CFString * dropString = SQLStr::GenDropTable(CFString(_S("Synopsis")));
   assert(dropString->Compare(_S("DROP TABLE IF EXISTS Synopsis")) == 0);
   
   // where clause
   ListCppObjT<SQLStr::SQLBaseClause> * whereClause = new ListCppObjT<SQLStr::SQLBaseClause>();
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("x"), CFString("<="), new Int32(333)));
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("and")));
   whereClause->AddTail(new SQLStr::SQLCondClause(new SQLStr::SQLSimpCond(CFString("y"), CFString("="), new CFString("hello")), 
                                                  CFString("or"), 
                                                  new SQLStr::SQLSimpCond(CFString("z"), CFString("="), new CFString("uuuuu"))));

   const CFString * whereString = SQLStr::GenWhere(*whereClause);
   assert(whereString->Compare(_S("x <= 333 and (y = 'hello' or z = 'uuuuu')")) == 0);

   // where clause
   whereClause = new ListCppObjT<SQLStr::SQLBaseClause>();
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("x"), CFString("<="), new Int64(I64N(837483937484))));
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("and")));
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("s"), CFString(">"), new UInt32(0xe0989032)));
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("and")));
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("r"), CFString(">"), new UInt64(U64N(0xffffe0989032))));
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("and")));
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("deadline"), CFString(">="), new DateTime(2012, 11, 2, 23, 59, 59, DateTime::DTK_UTC)));
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("and")));
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("y"), CFString("="), new CFString("'qwerty'")));

   whereString = SQLStr::GenWhere(*whereClause);
   assert(whereString->Compare(_S("x <= 837483937484 and s > 3768094770 and r > 281474449838130 and deadline >= '2012-11-02 23:59:59' and y = '''qwerty'''")) == 0);

   // select statement
   ListCppObjT<CFString> * cols = new ListCppObjT<CFString>();
   cols->AddTail(new CFString("key"));
   cols->AddTail(new CFString("id"));
   cols->AddTail(new CFString("start"));
   whereClause = new ListCppObjT<SQLStr::SQLBaseClause>();
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("start"), CFString(">"), new Int64(I64N(1310312100000))));
   whereString = SQLStr::GenWhere(*whereClause);
   const CFString * selectString = SQLStr::GenSelect(CFString(_S("Program")), *cols, *whereString, 
                                                     CFString("key"), CFString("id=100"), CFString("id"));
   assert(selectString->Compare(_S("SELECT key,id,start FROM Program WHERE start > 1310312100000 GROUP BY key HAVING id=100 ORDER BY id")) == 0);

   selectString = SQLStr::GenSelect(CFString(_S("Program")), *cols, *whereString, 
                                             CFString::Empty(), CFString::Empty(), CFString::Empty());
   assert(selectString->Compare(_S("SELECT key,id,start FROM Program WHERE start > 1310312100000")) == 0);

   // insert statement
   ListCppObjT<BaseObject> * colsAndValues = new ListCppObjT<BaseObject>();
   colsAndValues->AddTail(new CFString("key")); colsAndValues->AddTail(new CFString("1000"));
   colsAndValues->AddTail(new CFString("start")); colsAndValues->AddTail(new Int64(I64N(1310312100000)));
   colsAndValues->AddTail(new CFString("end")); colsAndValues->AddTail(new Int64(I64N(1310312112345)));
   SQLStr::PlaceHolder *placeHolder = new SQLStr::PlaceHolder(CFString("param1"));
   colsAndValues->AddTail(new CFString("content")); colsAndValues->AddTail(placeHolder);
   const CFString * insertString = SQLStr::GenInsert(CFString("Synopsis"), *colsAndValues);
   assert(insertString->Compare(_S("INSERT INTO Synopsis (key,start,end,content) VALUES ('1000',1310312100000,1310312112345,@p_param1)")) == 0);

   // update statement
   colsAndValues = new ListCppObjT<BaseObject>();
   colsAndValues->AddTail(new CFString("Synopsis_en")); colsAndValues->AddTail(new CFString("hello world"));
   colsAndValues->AddTail(new CFString("Synopsis_zh")); colsAndValues->AddTail(new CFString("Chinese is ok. I can't do it."));
   placeHolder = new SQLStr::PlaceHolder(CFString("myparam"));
   colsAndValues->AddTail(new CFString("Content")); colsAndValues->AddTail(placeHolder);
   whereClause = new ListCppObjT<SQLStr::SQLBaseClause>();
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("start"), CFString("="), new Int64(I64N(1310312100000))));
   const CFString * updateString = SQLStr::GenUpdate(CFString("Synopsis"), *colsAndValues, *SQLStr::GenWhere(*whereClause));
   assert(updateString->Compare(_S("UPDATE Synopsis SET Synopsis_en = 'hello world',Synopsis_zh = 'Chinese is ok. I can''t do it.',Content = @p_myparam WHERE start = 1310312100000")) == 0);

   // detele statement
   whereClause = new ListCppObjT<SQLStr::SQLBaseClause>();
   whereClause->AddTail(new SQLStr::SQLSimpCond(CFString("start"), CFString(">"), new Int64(I64N(1310312100000))));
   const CFString * deleteString = SQLStr::GenDelete(CFString("Synopsis"), *SQLStr::GenWhere(*whereClause));
   assert(deleteString->Compare(_S("DELETE FROM Synopsis WHERE start > 1310312100000")) == 0);

}

static void CreateTestTable(SQLiteDatabase *pDB)
{
   // create table
   pcwstr_t tableSchema[] = { 
                               _S("id"), _S("INTEGER PRIMARY KEY AUTOINCREMENT"), 
                               _S("start"), _S("DATETIME"), 
                               _S("end"), _S("DATETIME"),
                               _S("intvalue"), _S("INTEGER"),
                               _S("biginteger"), _S("BIGINT"),
                               _S("floatingval"), _S("DOUBLE"),
                               _S("rawdata"), _S("BLOB"),
                               _S("strcontent"), _S("TEXT"),
                               NULL
                            };

   ListCppObjT<CFString> * schemaList = toListObj(tableSchema);
   const CFString * createString = SQLStr::GenCreateTable(CFString(_S("mytable1")), *schemaList);

   SQLiteCommand *pCmd = new SQLiteCommand(pDB);
   pCmd->SetQueryString(*createString);
   assert(pCmd->ExecNonQuery());
   pCmd->Close();
}

static void InsertData(SQLiteDatabase *pDB, DateTime &curTime)
{
   ListCppObjT<BaseObject> * colsAndValues = new ListCppObjT<BaseObject>();
   DateTime *startTime = new DateTime(curTime);
   colsAndValues->AddTail(new CFString("start")); colsAndValues->AddTail(startTime);
   DateTime *pEnd = new DateTime(curTime);
   pEnd->AddDays(2).AddHours(3).AddMinutes(10);
   colsAndValues->AddTail(new CFString("end")); colsAndValues->AddTail(pEnd);
   colsAndValues->AddTail(new CFString("intvalue")); colsAndValues->AddTail(new Int32(11122));
   colsAndValues->AddTail(new CFString("biginteger")); colsAndValues->AddTail(new Int64(I64N(0x9123456780)));
   colsAndValues->AddTail(new CFString("floatingval")); colsAndValues->AddTail(new Double(35.912));
   SQLStr::PlaceHolder *placeHolder = new SQLStr::PlaceHolder(CFString("param1"));
   colsAndValues->AddTail(new CFString("rawdata")); colsAndValues->AddTail(placeHolder);
   SQLStr::PlaceHolder *placeHolder_2 = new SQLStr::PlaceHolder(CFString("param2"));
   colsAndValues->AddTail(new CFString("strcontent")); colsAndValues->AddTail(placeHolder_2);
   //colsAndValues->AddTail(new CFString("hello world - yes/no !"));
   const CFString * insertString = SQLStr::GenInsert(CFString("mytable1"), *colsAndValues);

   SQLiteCommand *pCmd = new SQLiteCommand(pDB);
   pCmd->SetQueryString(*insertString);
   // bind blob
   BinBuf *pBinBuf = new BinBuf(24);
   pBinBuf->AppendInt(10);
   pBinBuf->AppendInt(222);
   assert(pCmd->BindBlob(*placeHolder, *pBinBuf));
   // bind string
   CFString helloString("hello world - yes/no !");
   assert(pCmd->BindString(*placeHolder_2, helloString));

   assert(pCmd->ExecNonQuery());
   pCmd->Close();
}

static void ReadData(SQLiteDatabase *pDB, DateTime &curTime)
{
   ListCppObjT<CFString> * cols = new ListCppObjT<CFString>();
   cols->AddTail(new CFString("*"));
   const CFString * selectString = SQLStr::GenSelect(CFString("mytable1"), *cols, CFString::Empty(), CFString::Empty(),
                                                                                  CFString::Empty(), CFString::Empty());
   SQLiteCommand *pCmd = new SQLiteCommand(pDB);
   pCmd->SetQueryString(*selectString);
   SQLiteCursor *pCursor = pCmd->ExecQuery();
   while (pCursor->Read()) {
      assert(pCursor->GetColumnCount() == 8);

      // read datetime
      DateTime t(0);
      assert(pCursor->GetColumnType(1)->IsTypeOf(typeid(DateTime)));
      assert(pCursor->GetDateTime(CFString("start"), t));
      assert(t == curTime);
      assert(pCursor->GetColumnType(2)->IsTypeOf(typeid(DateTime)));
      assert(pCursor->GetDateTime(CFString("end"), t));
      DateTime endTime(curTime);
      endTime.AddDays(2).AddHours(3).AddMinutes(10);
      assert(t == endTime);
      
      // read integer and real
      int i1;
      int byteCount = pCursor->GetByteCount(3);
      assert(pCursor->GetColumnType(3)->IsTypeOf(typeid(Int32)));
      assert(pCursor->GetInt32(CFString("intvalue"), i1));
      assert(i1 == 11122);
      i64_t bInt1;
      byteCount = pCursor->GetByteCount(4);
      assert(pCursor->GetColumnType(4)->IsTypeOf(typeid(Int64)));
      assert(pCursor->GetInt64(4, bInt1));
      assert(bInt1 == I64N(0x9123456780));
      double vDou;
      assert(pCursor->GetColumnType(5)->IsTypeOf(typeid(Double)));
      assert(pCursor->GetDouble(5, vDou));
      assert(vDou > 35.9119999 && vDou < 35.9120001);

      // read blob
      BinBuf * pBuf = new BinBuf();
      assert(pCursor->GetColumnType(6)->IsTypeOf(typeid(BinBuf)));
      assert(pCursor->GetByteCount(6) == 5);
      assert(pCursor->GetBlob(6, *pBuf) == 5);
      assert(pBuf->GetRawBuf()[0] == '1');
      assert(pBuf->GetRawBuf()[1] == '0');
      assert(pBuf->GetRawBuf()[2] == '2');
      assert(pBuf->GetRawBuf()[3] == '2');
      assert(pBuf->GetRawBuf()[4] == '2');

      // read string
      CFString orgStr(_S("hello world - yes/no !"));
      CFString s;
      assert(pCursor->GetColumnType(7)->IsTypeOf(typeid(CFString)));
      assert(pCursor->GetUTF16CharCount(7) == orgStr.GetLength());
      assert(pCursor->GetString(7, s));
      assert(s == orgStr);

      // read column name
      pCursor->GetColumnName(0, s);
      assert(s == _S("id"));

      // read table name      
      pCursor->GetTableName(0, s);
      assert(s == _S("mytable1"));

      try {
         i1 = 0;
         pCursor->GetInt32(CFString("intvalue"), i1); // fetch again
         assert(i1 == 11122);
         pCursor->GetInt32(CFString("nointvalue"), i1);
         assert(false);
      }
      catch(SQLiteException &e) {
         debug::Print(debug::DL_DEBUG, _S("Error: %s\n"), e.GetMsg());
      }

      pCursor->GetDatabaseName(0, s);
   }

   pCursor->Close();
}

static void TestSQLWriteData()
{
   cppmempool::MemPoolWrap localPool;

   wc_t dbFile[] = _S("testsqlite.db");

   cppflib::os::DelFile(dbFile);

   SQLiteDatabase *pDB = new SQLiteDatabase();
   assert(pDB->Open(CFString(dbFile)));

   CreateTestTable(pDB);
   DateTime *curTime = DateTime::UtcNow();
   DateTime t(curTime->Year(), curTime->Month(), curTime->Day(), curTime->Hour(), curTime->Min(), curTime->Sec());
   InsertData(pDB, t);
   ReadData(pDB, t);

   pDB->Close();

   cppflib::os::DelFile(dbFile);
}

static void CheckNumRow(SQLiteDatabase *pDB, int expectedNumRow)
{
   ListCppObjT<CFString> * cols = new ListCppObjT<CFString>();
   cols->AddTail(new CFString("count(id)"));
   const CFString * selectString = SQLStr::GenSelect(CFString("mytable1"), *cols, CFString::Empty(), CFString::Empty(),
                                                                                  CFString::Empty(), CFString::Empty());
   SQLiteCommand *pCmd = new SQLiteCommand(pDB);
   pCmd->SetQueryString(*selectString);
   SQLiteCursor *pCursor = pCmd->ExecQuery();
   int val = 0;
   while (pCursor->Read()) {
      assert(pCursor->GetInt32(0, val));
      assert(val == expectedNumRow);
   }
   pCursor->Close();
   pCmd->Close();
}

static void InsertWithTransaction(SQLiteDatabase *pDB)
{
   InsertData(pDB, *DateTime::UtcNow());
   InsertData(pDB, *DateTime::UtcNow());
   InsertData(pDB, *DateTime::UtcNow());
   CheckNumRow(pDB, 3);

   // first transaction 
   SQLiteTransaction *pTran = new SQLiteTransaction(pDB);
   try {
      assert(pTran->Begin());
      InsertData(pDB, *DateTime::UtcNow());
      InsertData(pDB, *DateTime::UtcNow());
      InsertData(pDB, *DateTime::UtcNow());

      pTran->SetCommitOK();
   }
   catch (BaseException &e) {
      debug::Print(debug::DL_DEBUG, _S("Exception: %s\n"), e.GetMsg());
   }
   assert(pTran->End());
   pTran->Close();

   CheckNumRow(pDB, 6);

   // second transaction with failure
   pTran = new SQLiteTransaction(pDB);
   bool isThrow = true;
   try {
      assert(pTran->Begin());
      InsertData(pDB, *DateTime::UtcNow());
      InsertData(pDB, *DateTime::UtcNow());
      InsertData(pDB, *DateTime::UtcNow());

      if (isThrow)
         throw ApplicationException(_S("Throw an application exception inside a transaction"));

      pTran->SetCommitOK();
   }
   catch (BaseException &e) {
      debug::Print(debug::DL_DEBUG, _S("Exception: %s\n"), e.GetMsg());
   }
   assert(pTran->End());
   pTran->Close();

   CheckNumRow(pDB, 6); // all insert inside second transaction should have been abandoned

}

static void TestSQLTransaction()
{
   cppmempool::MemPoolWrap localPool;

   wc_t dbFile[] = _S("transsqlite.db");

   cppflib::os::DelFile(dbFile);
   SQLiteDatabase *pDB = new SQLiteDatabase();
   assert(pDB->Open(CFString(dbFile)));

   CreateTestTable(pDB);

   InsertWithTransaction(pDB);

   pDB->Close();

   cppflib::os::DelFile(dbFile);
}

static void CreateTestTable_2(SQLiteDatabase *pDB)
{
   // create table
   pcwstr_t tableSchema[] = { 
                               _S("myid"), _S("INTEGER"), 
                               _S("strcontent"), _S("TEXT"),
                               _S("data"), _S("BLOB"),
                               NULL
                            };

   ListCppObjT<CFString> * schemaList = toListObj(tableSchema);
   const CFString * createString = SQLStr::GenCreateTable(CFString(_S("mytable2")), *schemaList);

   SQLiteCommand *pCmd = new SQLiteCommand(pDB);
   pCmd->SetQueryString(*createString);
   assert(pCmd->ExecNonQuery());
   pCmd->Close();
}

static void InsertData_2(SQLiteDatabase *pDB, int startBlobNum)
{
   ListCppObjT<BaseObject> * colsAndValues = new ListCppObjT<BaseObject>();
   colsAndValues->AddTail(new CFString("myid")); colsAndValues->AddTail(new Int32(11122));
   SQLStr::PlaceHolder *placeHolder_2 = new SQLStr::PlaceHolder(CFString("param2"));
   colsAndValues->AddTail(new CFString("strcontent")); colsAndValues->AddTail(placeHolder_2);
   SQLStr::PlaceHolder *placeHolder_3 = new SQLStr::PlaceHolder(CFString("param3"));
   colsAndValues->AddTail(new CFString("data")); colsAndValues->AddTail(placeHolder_3);
   const CFString * insertString = SQLStr::GenInsert(CFString("mytable2"), *colsAndValues);

   SQLiteCommand *pCmd = new SQLiteCommand(pDB);
   pCmd->SetQueryString(*insertString);
   // bind string
   CFString helloString("hello world gogogo !!!");
   assert(pCmd->BindString(*placeHolder_2, helloString));

   // bind blob
   int len = startBlobNum + 10;
   BinBuf binBuf(len);
   u8_t data;
   for (int i = 0; i < static_cast<int>(len); ++i) {
      data = startBlobNum + i;
      binBuf.AppendData(&data, 1);
   }
   
   assert(pCmd->BindBlob(*placeHolder_3, binBuf));

   assert(pCmd->ExecNonQuery());
   pCmd->Close();
}

static void ReadBlob(SQLiteDatabase *pDB)
{
   ListCppObjT<CFString> * cols = new ListCppObjT<CFString>();
   cols->AddTail(new CFString("myid"));
   const CFString * selectString = SQLStr::GenSelectWithRowid(CFString("mytable2"), *cols, CFString::Empty());
   SQLiteCommand *pCmd = new SQLiteCommand(pDB);
   pCmd->SetQueryString(*selectString);
   SQLiteCursor *pCursor = pCmd->ExecQuery();
   BinBuf binBuf;
   i64_t val = 0;
   i64_t cmpRowid = 1;
   int startBlobNum = 0;
   while (pCursor->Read()) {
      assert(pCursor->GetInt64(1, val));
      assert(val == cmpRowid);
      cmpRowid++;

      SQLiteBlobIO *pBlobIO = pCursor->GetBlobIO(CFString("data"));

      int blobBytes = pBlobIO->GetBlobLength();
      assert(pBlobIO->Read(binBuf, 0, 0, blobBytes));
      for (int i = 0; i < static_cast<int>(binBuf.GetValidLength()); ++i) {
         assert(binBuf.GetRawBuf()[i] == startBlobNum + i);
      }

      cppmempool::Release(pBlobIO);
      ++startBlobNum;
   }
   pCursor->Close();
   pCmd->Close();
}

static void WriteBlob(SQLiteDatabase *pDB)
{
   ListCppObjT<CFString> * cols = new ListCppObjT<CFString>();
   cols->AddTail(new CFString(SQLiteDatabase::GetConstName(SQLiteDatabase::ROWID)));
   const CFString * selectString = SQLStr::GenSelect(CFString("mytable2"), *cols, CFString::Empty(), CFString::Empty(),
                                                                                  CFString::Empty(), CFString::Empty());

   // overwrite blob
   SQLiteCommand *pCmd = new SQLiteCommand(pDB);
   SQLiteBlobIO *pBlobIO = new SQLiteBlobIO(pDB);
   pCmd->SetQueryString(*selectString);
   SQLiteCursor *pCursor = pCmd->ExecQuery();
   BinBuf binBuf;
   i64_t val = 0;
   i64_t cmpRowid = 1;
   int startBlobNum = 0;
   while (pCursor->Read()) {
      assert(pCursor->GetInt64(0, val));
      assert(val == cmpRowid);
      cmpRowid++;

      if (val == 1)
         assert(pBlobIO->Open(*pCursor->GetDatabaseName(0), *pCursor->GetTableName(0), CFString("data"), val, false));
      else 
         assert(pBlobIO->Reopen(val));

      int blobBytes = pBlobIO->GetBlobLength();
      binBuf.SetValidLength(0);
      u8_t data = static_cast<u8_t>('a' + val);
      for (int i = 0; i < blobBytes; ++i) {
         binBuf.AppendData(&data, 1);
      }

      assert(pBlobIO->Write(binBuf, 0, 1, blobBytes - 2)); // overwrite except head and tail
   }

   pBlobIO->Close();
   pCursor->Close();
   pCmd->Close();

   // read back to check 
   pCmd = new SQLiteCommand(pDB);
   pBlobIO = new SQLiteBlobIO(pDB);
   pCmd->SetQueryString(*selectString);
   pCursor = pCmd->ExecQuery();
   binBuf.ClearBuf();
   binBuf.SetValidLength(0);
   val = 0;
   startBlobNum = 0;
   
   while (pCursor->Read()) {
      assert(pCursor->GetInt64(0, val));
      
      if (val == 1)
         assert(pBlobIO->Open(*pCursor->GetDatabaseName(0), *pCursor->GetTableName(0), CFString("data"), val, true));
      else 
         assert(pBlobIO->Reopen(val));

      int blobBytes = pBlobIO->GetBlobLength();
      u8_t data = static_cast<u8_t>('a' + val);
      assert(pBlobIO->Read(binBuf, 0, 0, blobBytes));
      for (int i = 0; i < static_cast<int>(binBuf.GetValidLength()); ++i) {
         if (i == 0 || i == static_cast<int>(binBuf.GetValidLength()) - 1)  // head and tail are numbers
            assert(binBuf.GetRawBuf()[i] == startBlobNum + i);
         else
            assert(binBuf.GetRawBuf()[i] == data);
      }

      ++startBlobNum;
   }

   pBlobIO->Close();
   pCursor->Close();
   pCmd->Close();


}

static void TestReadWriteBlob()
{
   cppmempool::MemPoolWrap localPool;

   wc_t dbFile[] = _S("testreadwriteblob.db");

   cppflib::os::DelFile(dbFile);
   SQLiteDatabase *pDB = new SQLiteDatabase();
   assert(pDB->Open(CFString(dbFile)));

   CreateTestTable_2(pDB);
   for (int i = 0; i < 10; ++i) 
      InsertData_2(pDB, i);

   ReadBlob(pDB);
   WriteBlob(pDB);

   pDB->Close();
   cppflib::os::DelFile(dbFile);
}


void TestSqlite(void)
{
   debug::Print(_S("Testing SQLite ...\n"));
   
   TestSQLStr();
   TestSQLWriteData();
   TestSQLTransaction();
   TestReadWriteBlob();
}